/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.security.logging.log4j;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.vacoor.nothing.security.logging.CircularList;
import org.vacoor.nothing.security.logging.ListenerConfig;
import org.vacoor.nothing.security.logging.LogWatcher;
import org.vacoor.nothing.security.logging.LoggerInfo;

import java.util.*;

//import org.apache.solr.common.SolrDocument;

public class Log4jWatcher extends LogWatcher<LoggingEvent> {
    private final String name;
    private AppenderSkeleton appender = null;

    public Log4jWatcher(String name) {
        this.name = name;
    }

    public String getName() {
        return "Log4j (" + this.name + ")";
    }

    public List<String> getAllLevels() {
        return Arrays.asList(new String[]{Level.ALL.toString(), Level.TRACE.toString(), Level.DEBUG.toString(), Level.INFO.toString(), Level.WARN.toString(), Level.ERROR.toString(), Level.FATAL.toString(), Level.OFF.toString()});
    }

    public void setLogLevel(String category, String level) {
        Logger log;
        if ("root".equals(category))
            log = LogManager.getRootLogger();
        else {
            log = Logger.getLogger(category);
        }
        if ((level == null) || ("unset".equals(level)) || ("null".equals(level))) {
            log.setLevel(null);
        } else
            log.setLevel(Level.toLevel(level));
    }

    public Collection<LoggerInfo> getAllLoggers() {
        Logger root = LogManager.getRootLogger();
        Map map = new HashMap();
        Enumeration loggers = LogManager.getCurrentLoggers();
        while (loggers.hasMoreElements()) {
            Logger logger = (Logger) loggers.nextElement();
            String name = logger.getName();
            if (logger != root) {
                map.put(name, new Log4jInfo(name, logger));
                while (true) {
                    int dot = name.lastIndexOf(".");
                    if (dot < 0)
                        break;
                    name = name.substring(0, dot);
                    if (!map.containsKey(name))
                        map.put(name, new Log4jInfo(name, null));
                }
            }
        }
        map.put("root", new Log4jInfo("root", root));
        return map.values();
    }

    public void setThreshold(String level) {
        if (this.appender == null) {
            throw new IllegalStateException("Must have an appender");
        }
        this.appender.setThreshold(Level.toLevel(level));
    }

    public String getThreshold() {
        if (this.appender == null) {
            throw new IllegalStateException("Must have an appender");
        }
        return this.appender.getThreshold().toString();
    }

    public void registerListener(ListenerConfig cfg) {
        if (this.history != null) {
            throw new IllegalStateException("History already registered");
        }
        this.history = new CircularList(cfg.size);

        this.appender = new EventAppender(this);
        if (cfg.threshold != null) {
            this.appender.setThreshold(Level.toLevel(cfg.threshold));
        } else {
            this.appender.setThreshold(Level.WARN);
        }
        Logger log = LogManager.getRootLogger();
        log.addAppender(this.appender);
    }

    public long getTimestamp(LoggingEvent event) {
        return event.timeStamp;
    }

    /*
    public SolrDocument toSolrDocument(LoggingEvent event) {
        SolrDocument doc = new SolrDocument();
        doc.setField("time", new Date(event.getTimeStamp()));
        doc.setField("level", event.getLevel().toString());
        doc.setField("logger", event.getLogger().getName());
        doc.setField("message", event.getRenderedMessage());
        ThrowableInformation t = event.getThrowableInformation();
        if (t != null) {
            doc.setField("trace", Throwables.getStackTraceAsString(t.getThrowable()));
        }
        return doc;
    }
    */
}